package com.joyxy.easy.monitor;

import cn.hutool.log.Log;
import cn.sanenen.dm.base.DmApi;
import com.joyxy.easy.entity.OtherConfig;
import com.joyxy.easy.entity.SkillConfig;
import com.joyxy.easy.entity.StatusConfig;
import com.joyxy.easy.entity.WindowContext;
import com.joyxy.easy.service.MoveService;
import com.joyxy.easy.manger.WindowManager;

import javax.swing.*;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;

public class AutomationRunner {
    private Log log = Log.get();
    private final long hwnd;
    private final List<SkillConfig> skillConfigs;
    private final StatusConfig statusConfig;
    private final OtherConfig otherConfig;
    private volatile boolean running = false;

    private ScheduledExecutorService executorService;
    private final List<ScheduledFuture<?>> scheduledTasks = new ArrayList<>();

    private Thread monitorThread;
    private Thread dmPressKeyThread;
    private Thread lockAddrThread;
    private Thread pickupThread;
    private Thread moveLeftRightThread;

    private LinkedBlockingDeque<SkillConfig> keys = new LinkedBlockingDeque<>();
    private MoveService moveService;
    private final Object moveLock = new Object();
    private int time = 0;


    public AutomationRunner(long hwnd, List<SkillConfig> skillConfigs, StatusConfig statusConfig, OtherConfig otherConfig) {
        this.hwnd = hwnd;
        this.skillConfigs = skillConfigs;
        this.statusConfig = statusConfig;
        this.otherConfig = otherConfig;
        this.moveService = new MoveService(hwnd);
    }

    public synchronized void start() {
        stop(); // 确保之前的任务已结束

        running = true;
        System.out.println("开始自动化");

        executorService = Executors.newScheduledThreadPool(skillConfigs.size() + 8);

        startSkill();

        monitorThread = createAndStartThread(this::runStatusMonitor, "StatusMonitor");
        dmPressKeyThread = createAndStartThread(this::runDmPressKey, "DmPressKey");

        if (otherConfig.isLockAddress()) {
            lockAddrThread = createAndStartThread(this::runLockAddress, "LockAddress");
        }

        if (otherConfig.isPick()) {
            pickupThread = createAndStartThread(this::runPickUp, "PickUp");
        }

        moveLeftRightThread = createAndStartThread(this::moveLeftRight, "MoveLeftRight");
        new Timer(1000, e -> updateTime()).start();
    }

    private void updateTime() {
        if(running){
            this.time++;
        }
    }

    private Thread createAndStartThread(Runnable task, String name) {
        Thread t = new Thread(task, name);
        t.setDaemon(true);
        t.start();
        return t;
    }

    public void startSkill() {
        for (ScheduledFuture<?> task : scheduledTasks) {
            task.cancel(true);
        }
        scheduledTasks.clear();

        for (SkillConfig config : skillConfigs) {
            try {
                int interval = Integer.parseInt(config.intervalText);
                if ("分".equals(config.unit)) {
                    interval *= 60;
                }
                ScheduledFuture<?> future = executorService.scheduleAtFixedRate(
                        () -> executeSkill(config),
                        0,
                        interval,
                        TimeUnit.SECONDS
                );
                scheduledTasks.add(future);
            } catch (NumberFormatException e) {
                log.info("无效的间隔时间: " + config.intervalText);
            }
        }
    }

    private void moveLeftRight() {
        while (running && !Thread.currentThread().isInterrupted()) {
            try {
                if (canRun()) {
                    executeMoveLeftRight();
                }
                Thread.sleep(120_000);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                break;
            }
        }
    }

    private void executeMoveLeftRight() {
        // TODO: 填充左右移动逻辑
    }

    private void runPickUp() {
        while (running && !Thread.currentThread().isInterrupted()) {
            try {
                WindowContext context = WindowManager.getContext(hwnd);
                DmApi dmApi = context.getDmApi();
                dmApi.KeyPressChar("c");
                Thread.sleep(500);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                break;
            }
        }
    }

    private void runLockAddress() {
        WindowContext context = WindowManager.getContext(hwnd);
        StatusMonitor monitor = context.getMonitor();
        while (running && !Thread.currentThread().isInterrupted() && otherConfig.isLockAddress()) {
            synchronized (moveLock) {
                if (canRun()) {
                    long x = monitor.getX();
                    if (Math.abs(x - otherConfig.getLockX()) > 5) {
                        log.info(">>>>>坐标与设置的不一致，需要移动");
                        if (otherConfig.isLockFace()) {
                            moveService.move(otherConfig.getLockX(), otherConfig.getFace());
                        } else {
                            moveService.move(otherConfig.getLockX(), null);
                        }
                        log.info(">>>>>锁定坐标移动完成");
                    }
                }
            }
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                break;
            }
        }
    }

    private void runDmPressKey() {
        while (running && !Thread.currentThread().isInterrupted()) {
            try {
                if (keys != null && canRun()) {
                    SkillConfig keyConfig = keys.take();
                    if (keyConfig.buff) {
                        Thread.sleep(1000);
                    }
                    String key = keyConfig.key;
                    WindowContext context = WindowManager.getContext(hwnd);
                    DmApi dmApi = context.getDmApi();
                    dmApi.KeyPressChar(key);
                    dmApi.KeyPressChar(key);
                    dmApi.KeyPressChar(key);
                    log.info("发送按键: " + key);
                    Thread.sleep(600);
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                break;
            } catch (Exception e) {
                log.info(e.getMessage());
            }
        }
    }

    public synchronized void stop() {
        if (!running) return;
        running = false;
        time = 0;
        System.out.println("停止自动化");

        interruptThread(monitorThread);
        interruptThread(dmPressKeyThread);
        interruptThread(lockAddrThread);
        interruptThread(pickupThread);
        interruptThread(moveLeftRightThread);

        if (keys != null) {
            keys.clear();
        }

        if (executorService != null) {
            executorService.shutdownNow();
            try {
                if (!executorService.awaitTermination(2, TimeUnit.SECONDS)) {
                    log.warn("线程池未能在2秒内关闭");
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
            executorService = null;
        }
    }

    private void interruptThread(Thread t) {
        if (t != null && t.isAlive()) {
            t.interrupt();
        }
    }

    public boolean isRunning() {
        return running;
    }

    private void executeSkill(SkillConfig config) {
        if (!canRun()) return;
        try {
            keys.put(config);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }

    private boolean canRun() {
        return running
                && !WindowManager.getContext(hwnd).getMonitor().isMove()
                && !WindowManager.getContext(hwnd).getMonitor().isSell();
    }

    private void runStatusMonitor() {
        try {
            WindowContext context = WindowManager.getContext(hwnd);
            DmApi dmApi = context.getDmApi();
            StatusMonitor monitor = context.getMonitor();
            while (running && !Thread.currentThread().isInterrupted()) {
                double currentHp = monitor.getHp();
                double currentMp = monitor.getMp();
                long currentDebuff = monitor.getDebuff();

                if (statusConfig.hpCheck && !statusConfig.hpThreshold.isEmpty()
                        && currentHp < Integer.parseInt(statusConfig.hpThreshold)) {
                    dmApi.KeyPressChar(statusConfig.hpKey);
                    log.info("血量低，按下: " + statusConfig.hpKey);
                    if (statusConfig.debuffCheck && !statusConfig.debuffKey.isEmpty()) {
                        dmApi.KeyPressChar(statusConfig.debuffKey);
                        log.info("血量低，吃卵: " + statusConfig.hpKey);
                    }
                }
                if (statusConfig.mpCheck && !statusConfig.mpThreshold.isEmpty()
                        && currentMp < Integer.parseInt(statusConfig.mpThreshold)) {
                    dmApi.KeyPressChar(statusConfig.mpKey);
                    log.info("魔法低，按下: " + statusConfig.mpKey);
                }
                if (statusConfig.debuffCheck && !statusConfig.debuffThreshold.isEmpty()
                        && currentDebuff >= Long.parseLong(statusConfig.debuffThreshold)) {
                    dmApi.KeyPressChar(statusConfig.debuffKey);
                    log.info("debuff太多，吃卵: " + statusConfig.debuffKey);
                }
                Thread.sleep(200);
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        } catch (NumberFormatException e) {
            log.info("无效的阈值配置");
        }
    }

    public void setLockX(long lockX) {
        if (otherConfig != null) {
            otherConfig.setLockX(lockX);
        }
    }

    public String getTime() {
        return time + "";
    }
}

